/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package Modele.Droit.Regles;

import Modele.Droit.Entites.*;
import Modele.Droit.RBAC.*;
import Modele.Utilisateur;
import java.sql.CallableStatement;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Types;
import java.util.ArrayList;	
import java.util.UUID;

/**
 *
 * @author Cyril
 */
public class Regles 
{
    private Connection mConnection;
    
    private String mServer = "database.oragon.net";
    private String mDBName = "bcfr";
    private String mUser = "bcfr";
    private String mPassword = "supinfo";
    
    private CallableStatement mGetIdAction;
    private CallableStatement mSetRole;
    private CallableStatement mUnsetRole;
    private CallableStatement mGetRoles;
    private CallableStatement mGetRolesUtilisateur;
    private CallableStatement mGetUtilisateursRole;
    private CallableStatement mSetVue;
    private CallableStatement mUnsetVue;
    private CallableStatement mGetVues;
    private CallableStatement mGetVuesObjet;
    private CallableStatement mGetObjetsVue;
    private CallableStatement mSetHabilite;
    private CallableStatement mUnsetHabilite;
    private CallableStatement mSetConsidere;
    private CallableStatement mUnsetConsidere;
    private CallableStatement mSetPermissionAbstraite;
    private CallableStatement mUnsetPermissionAbstraite;
    private CallableStatement mSetPermissionConcrete;
    private CallableStatement mUnsetPermissionConcrete;
        
    public Regles(String pServer, String pDBName, String pUser, String pPassword) throws ClassNotFoundException, SQLException
    {
        Class.forName("org.postgresql.Driver");
        mConnection = DriverManager.getConnection("jdbc:postgresql://"+pServer+":5432/"+pDBName,pUser, pPassword);
        
        initCalls();
    }
    
    public Regles() throws ClassNotFoundException, SQLException
    {
        Class.forName("org.postgresql.Driver");
        mConnection = DriverManager.getConnection("jdbc:postgresql://"+mServer+":5432/"+mDBName,mUser, mPassword);
        
        initCalls();
    }
    
    /* Initialise toutes les requêtes sql */
    private void initCalls() throws SQLException
    {
        /* Prépare toutes les requetes */
        mGetIdAction = mConnection.prepareCall("{call \"GetIdAction\" (?) }");
        
        mSetRole = mConnection.prepareCall("{? = call \"SetRole\" (?::uuid, ?) }");
        mSetRole.registerOutParameter(1, Types.BOOLEAN);
        
        mUnsetRole = mConnection.prepareCall("{? = call \"UnsetRole\" (?::uuid) }");
        mUnsetRole.registerOutParameter(1, Types.BOOLEAN);
        
        mGetRoles = mConnection.prepareCall("{call \"GetRoles\" () }");
        
        mGetRolesUtilisateur = mConnection.prepareCall("{call \"GetRolesUtilisateur\" (?::uuid) }");
        
        mGetUtilisateursRole = mConnection.prepareCall("{call \"GetUtilisateursRole\" (?::uuid) }");
        
        mSetVue = mConnection.prepareCall("{? = call \"SetVue\" (?::uuid, ?) }");
        mSetVue.registerOutParameter(1, Types.BOOLEAN);
        
        mUnsetVue = mConnection.prepareCall("{? = call \"UnsetVue\" (?::uuid) }");
        mUnsetVue.registerOutParameter(1, Types.BOOLEAN);
        
        mGetVues = mConnection.prepareCall("{call \"GetVues\" () }");
        
        mGetVuesObjet = mConnection.prepareCall("{call \"GetVuesObjet\" (?::uuid) }");
        
        mGetObjetsVue = mConnection.prepareCall("{call \"GetObjetsVue\" (?::uuid) }");
        
        mSetHabilite = mConnection.prepareCall("{? = call \"SetHabilite\" (?::uuid, ?::uuid) }");
        mSetHabilite.registerOutParameter(1, Types.BOOLEAN);
        
        mUnsetHabilite = mConnection.prepareCall("{? = call \"UnsetHabilite\" (?::uuid, ?::uuid) }");
        mUnsetHabilite.registerOutParameter(1, Types.BOOLEAN);
        
        mSetConsidere = mConnection.prepareCall("{? = call \"SetConsidere\" (?::uuid, ?::uuid) }");
        mSetConsidere.registerOutParameter(1, Types.BOOLEAN);
        
        mUnsetConsidere = mConnection.prepareCall("{? = call \"UnsetConsidere\" (?::uuid, ?::uuid) }");
        mUnsetConsidere.registerOutParameter(1, Types.BOOLEAN);
        
        mSetPermissionAbstraite = mConnection.prepareCall("{? = call \"SetPermissionAbstraite\" (?::uuid, ?::uuid, ?::uuid) }");
        mSetPermissionAbstraite.registerOutParameter(1, Types.BOOLEAN);
        
        mUnsetPermissionAbstraite = mConnection.prepareCall("{? = call \"UnsetPermissionAbstraite\" (?::uuid, ?::uuid, ?::uuid) }");
        mUnsetPermissionAbstraite.registerOutParameter(1, Types.BOOLEAN);
        
        mSetPermissionConcrete = mConnection.prepareCall("{? = call \"SetPermissionConcrete\" (?::uuid, ?::uuid, ?::uuid) }");
        mSetPermissionConcrete.registerOutParameter(1, Types.BOOLEAN);
        
        mUnsetPermissionConcrete = mConnection.prepareCall("{? = call \"UnsetPermissionConcrete\" (?::uuid, ?::uuid, ?::uuid) }");
        mUnsetPermissionConcrete.registerOutParameter(1, Types.BOOLEAN);
    }
    
    /* Recupère l'id d'une action */
    public UUID getIdAction(String pNom) throws SQLException
    {
        ArrayList<UUID> vIdAction = new ArrayList<UUID>();

        mConnection.setAutoCommit(false);
        mGetIdAction.setString(1, pNom);
        ResultSet vResultSet = mGetIdAction.executeQuery();
        mConnection.commit();

        while(vResultSet.next())
            vIdAction.add(UUID.fromString(vResultSet.getString("id")));
        vResultSet.close();

        return vIdAction.get(0);
    }

    /* Ajoute ou modifie un role dans la BDD */
    public boolean setRole(Role pRole) throws SQLException
    {
        mConnection.setAutoCommit(false);
        mSetRole.setString(2, pRole.getIdRole().toString());
        mSetRole.setString(3, pRole.getNom());
        System.out.println(mSetRole.toString());
        mSetRole.execute();
        mConnection.commit();
        
        return mSetRole.getBoolean(1);
    }
    
    /* Supprime un role */
    public boolean unsetRole(Role pRole) throws SQLException
    {
        mConnection.setAutoCommit(false);
        mUnsetRole.setString(2, pRole.getIdRole().toString());
        
        mUnsetRole.execute();
        mConnection.commit();
        
        return mUnsetRole.getBoolean(1);
    }
    
    /* Retourne la liste de tous les roles */
    public ArrayList<Role> getRoles() throws SQLException
    {
        ArrayList<Role> vListeRoles = new ArrayList<Role>();
        
        mConnection.setAutoCommit(false);
        ResultSet vResultSet = mGetRoles.executeQuery();
        mConnection.commit();
        
        while(vResultSet.next())
            vListeRoles.add(new Role(UUID.fromString(vResultSet.getString("id")), vResultSet.getString("nom")));
        vResultSet.close();
        
        return vListeRoles;
    }
    
    /* Retourne la liste des roles d'un utilisateur */
    public ArrayList<Role> getRolesUtilisateur(Utilisateur pUtilisateur) throws SQLException
    {
        ArrayList<Role> vListeRoles = new ArrayList<Role>();
        
        mConnection.setAutoCommit(false);        
        mGetRolesUtilisateur.setString(1, pUtilisateur.getId().toString());
        
        ResultSet vResultSet = mGetRolesUtilisateur.executeQuery();
        mConnection.commit();
        
        while(vResultSet.next())
            vListeRoles.add(new Role(UUID.fromString(vResultSet.getString("id")), vResultSet.getString("nom")));
        vResultSet.close();
        
        return vListeRoles;
    }
    
    /* Retourne tous les utilisateurs d'un role */
    public ArrayList<UUID> getUtilisateursRole(Role pRole) throws SQLException
    {
        ArrayList<UUID> vListeIdUtilisateurs = new ArrayList<UUID>();
        
        mConnection.setAutoCommit(false);        
        mGetUtilisateursRole.setString(1, pRole.getIdRole().toString());
        
        ResultSet vResultSet = mGetUtilisateursRole.executeQuery();
        mConnection.commit();
        
        while(vResultSet.next())
            vListeIdUtilisateurs.add(UUID.fromString(vResultSet.getString("id_utilisateur")));
        vResultSet.close();
        
        return vListeIdUtilisateurs;
    }
    
    
    /* Ajoute ou modifie une vue dans la BDD */
    public boolean setVue(Vue pVue) throws SQLException
    {
        mConnection.setAutoCommit(false);
        mSetVue.setString(2, pVue.getIdVue().toString());
        mSetVue.setString(3, pVue.getNom());
        
        mSetVue.execute();
        mConnection.commit();
        
        return mSetVue.getBoolean(1);
    }
    
    /* Supprime une vue */
    public boolean unsetVue(Vue pVue) throws SQLException
    {
        mConnection.setAutoCommit(false);
        mUnsetVue.setString(2, pVue.getIdVue().toString());
        
        mUnsetVue.execute();
        mConnection.commit();
        
        return mUnsetVue.getBoolean(1);
    }
    
    /* Renvoie une liste de toutes les vues */
    public ArrayList<Vue> getVues() throws SQLException
    {
        ArrayList<Vue> vListeVues = new ArrayList<Vue>();
        
        mConnection.setAutoCommit(false);        
        ResultSet vResultSet = mGetVues.executeQuery();
        mConnection.commit();
        
        while(vResultSet.next())
            vListeVues.add(new Vue(UUID.fromString(vResultSet.getString("id")), vResultSet.getString("nom")));
        vResultSet.close();
        
        return vListeVues;
    }
    
    /* Retourne toutes les vues d'un objet */
    public ArrayList<Vue> getVuesObjet(IObjet pObjet) throws SQLException
    {
        ArrayList<Vue> vListeVues = new ArrayList<Vue>();
        
        mConnection.setAutoCommit(false);        
        mGetVuesObjet.setString(1, pObjet.getId().toString());
        
        ResultSet vResultSet = mGetVuesObjet.executeQuery();
        mConnection.commit();
        
        while(vResultSet.next())
            vListeVues.add(new Vue(UUID.fromString(vResultSet.getString("id")), vResultSet.getString("nom")));
        vResultSet.close();
        
        return vListeVues;
    }
    
    /* Retourne tous les objets d'une vue */
    public ArrayList<UUID> getObjetsVue(Vue pVue) throws SQLException
    {
        ArrayList<UUID> vListeIdObjets = new ArrayList<UUID>();
        
        mConnection.setAutoCommit(false);        
        mGetObjetsVue.setString(1, pVue.getIdVue().toString());
        
        ResultSet vResultSet = mGetObjetsVue.executeQuery();
        mConnection.commit();
        
        while(vResultSet.next())
            vListeIdObjets.add(UUID.fromString(vResultSet.getString("id_objet")));
        vResultSet.close();
        
        return vListeIdObjets;
    }
    
    /* Ajoute un utilisateur dans un role */
    public boolean setHabilite(Utilisateur pUtilisateur, Role pRole) throws SQLException
    {        
        mConnection.setAutoCommit(false);
        mSetHabilite.setString(2, pUtilisateur.getId().toString());
        mSetHabilite.setString(3, pRole.getIdRole().toString());
        
        mSetHabilite.execute();
        mConnection.commit();
        
        return mSetHabilite.getBoolean(1);
    }

    /* Supprime un utilisateur d'un role */
    public boolean unsetHabilite(Utilisateur pUtilisateur, Role pRole) throws SQLException
    {        
        mConnection.setAutoCommit(false);
        mUnsetHabilite.setString(2, pUtilisateur.getId().toString());
        mUnsetHabilite.setString(3, pRole.getIdRole().toString());
        
        mUnsetHabilite.execute();
        mConnection.commit();
        
        return mUnsetHabilite.getBoolean(1);
    }
    
    /* Ajoute un objet dans une vue */
    public boolean setConsidere(IObjet pObjet, Vue pVue) throws SQLException
    {        
        mConnection.setAutoCommit(false);
        mSetConsidere.setString(2, pObjet.getId().toString());
        mSetConsidere.setString(3, pVue.getIdVue().toString());
        
        mSetConsidere.execute();
        mConnection.commit();
        
        return mSetConsidere.getBoolean(1);
    }
    
    /* Supprime un objet d'une vue */
    public boolean unsetConsidere(IObjet pObjet, Vue pVue) throws SQLException
    {        
        mConnection.setAutoCommit(false);
        mUnsetConsidere.setString(2, pObjet.getId().toString());
        mUnsetConsidere.setString(3, pVue.getIdVue().toString());
        
        mUnsetConsidere.execute();
        mConnection.commit();
        
        return mUnsetConsidere.getBoolean(1);
    }
    
    /* Ajoute une permission abstraite */
    public boolean setPermission(Role pRole, Vue pVue, Action pAction) throws SQLException
    {
        mConnection.setAutoCommit(false);
        mSetPermissionAbstraite.setString(2, pRole.getIdRole().toString());
        mSetPermissionAbstraite.setString(3, pVue.getIdVue().toString());
        mSetPermissionAbstraite.setString(4, pAction.getIdAction().toString());
        
        mSetPermissionAbstraite.execute();
        mConnection.commit();
        
        return mSetPermissionAbstraite.getBoolean(1);
    }
    
    /* Supprime une permission abstraite */
    public boolean unsetPermission(Role pRole, Vue pVue, Action pAction) throws SQLException
    {
        mConnection.setAutoCommit(false);
        mUnsetPermissionAbstraite.setString(2, pRole.getIdRole().toString());
        mUnsetPermissionAbstraite.setString(3, pVue.getIdVue().toString());
        mUnsetPermissionAbstraite.setString(4, pAction.getIdAction().toString());
        
        mUnsetPermissionAbstraite.execute();
        mConnection.commit();
        
        return mUnsetPermissionAbstraite.getBoolean(1);
    }
    
    /* Ajoute une permission concrète */
    public boolean setPermission(Utilisateur pUtilisateur, IObjet pObjet, Action pAction) throws SQLException
    {
        mConnection.setAutoCommit(false);
        mSetPermissionConcrete.setString(2, pUtilisateur.getId().toString());
        mSetPermissionConcrete.setString(3, pObjet.getId().toString());
        mSetPermissionConcrete.setString(4, pAction.getIdAction().toString());
        
        mSetPermissionConcrete.execute();
        mConnection.commit();
        
        return mSetPermissionConcrete.getBoolean(1);
    }
    
    /* Supprime une permission concrete */
    public boolean unsetPermission(Utilisateur pUtilisateur, IObjet pObjet, Action pAction) throws SQLException
    {
        mConnection.setAutoCommit(false);
        mUnsetPermissionConcrete.setString(2, pUtilisateur.getId().toString());
        mUnsetPermissionConcrete.setString(3, pObjet.getId().toString());
        mUnsetPermissionConcrete.setString(4, pAction.getIdAction().toString());
        
        mUnsetPermissionConcrete.execute();
        mConnection.commit();
        
       return mUnsetPermissionConcrete.getBoolean(1);       
    }
}
